package com.blog4j.article.service.impl;

import cn.dev33.satoken.stp.StpUtil;
import cn.hutool.core.collection.CollectionUtil;
import com.alibaba.fastjson.JSON;
import com.alibaba.fastjson.JSONArray;
import com.alibaba.fastjson.JSONObject;
import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper;
import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl;
import com.blog4j.api.client.FeignSystem;
import com.blog4j.api.client.FeignUser;
import com.blog4j.api.vo.OrganizationVo;
import com.blog4j.api.vo.SystemBaseConfigVo;
import com.blog4j.api.vo.UserInfoVo;
import com.blog4j.article.context.CreateArticleContext;
import com.blog4j.article.context.UpdateArticleContext;
import com.blog4j.article.entity.ApplyArticleEntity;
import com.blog4j.article.entity.ArticleEntity;
import com.blog4j.article.entity.CategoryEntity;
import com.blog4j.article.entity.CategoryLabelRelEntity;
import com.blog4j.article.entity.CommentEntity;
import com.blog4j.article.entity.FavoriteEntity;
import com.blog4j.article.entity.LabelEntity;
import com.blog4j.article.mapper.ApplyArticleMapper;
import com.blog4j.article.mapper.ArticleMapper;
import com.blog4j.article.mapper.CategoryLabelRelMapper;
import com.blog4j.article.mapper.CategoryMapper;
import com.blog4j.article.mapper.CommentMapper;
import com.blog4j.article.mapper.FavoriteMapper;
import com.blog4j.article.mapper.LabelMapper;
import com.blog4j.article.service.ArticleService;
import com.blog4j.article.vo.req.ArticleByCategoryIdReqVo;
import com.blog4j.article.vo.req.ArticleListReqVo;
import com.blog4j.article.vo.req.FavoriteArticleByUserIdReqVo;
import com.blog4j.article.vo.req.FavoriteReqVo;
import com.blog4j.article.vo.req.LikeArticleReqVo;
import com.blog4j.article.vo.req.UserArticleReqVo;
import com.blog4j.article.vo.resp.ArticleCategoryNumsRespVo;
import com.blog4j.article.vo.resp.ArticleRespVo;
import com.blog4j.article.vo.resp.ArticleStatusRespVo;
import com.blog4j.common.constants.CacheConstants;
import com.blog4j.common.constants.CommonConstant;
import com.blog4j.common.enums.ApproveEnum;
import com.blog4j.common.enums.ArticlePublicTypeEnum;
import com.blog4j.common.enums.ArticleStatusEnum;
import com.blog4j.common.enums.ArticleTypeEnum;
import com.blog4j.common.enums.CategoryAndLabelStatusEnum;
import com.blog4j.common.enums.ErrorEnum;
import com.blog4j.common.enums.RoleEnum;
import com.blog4j.common.enums.YesOrNoEnum;
import com.blog4j.common.exception.Blog4jException;
import com.blog4j.common.utils.CommonUtil;
import com.blog4j.common.utils.IdGeneratorSnowflakeUtil;
import com.blog4j.api.vo.DeleteUserArticleVo;
import com.blog4j.common.utils.RedisUtil;
import com.fasterxml.jackson.databind.ObjectMapper;
import com.github.pagehelper.Page;
import com.github.pagehelper.PageHelper;
import com.github.pagehelper.PageInfo;
import lombok.RequiredArgsConstructor;
import org.apache.commons.lang.StringUtils;
import org.springframework.beans.BeanUtils;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;
import org.springframework.util.CollectionUtils;

import java.util.ArrayList;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
import java.util.Objects;
import java.util.Set;
import java.util.stream.Collectors;

/**
 * @author 98k灬
 * @version v1.0.0
 * @Description : 功能描述
 * @Create on : 2024/6/28 13:03
 **/
@Service
@RequiredArgsConstructor(onConstructor_ = @Autowired)
public class ArticleServiceImpl extends ServiceImpl<ArticleMapper, ArticleEntity> implements ArticleService {
    private final CategoryMapper categoryMapper;
    private final FeignUser feignUser;
    private static final int DEFAULT_PAGE_SIZE = 10;
    private final LabelMapper labelMapper;
    private final ApplyArticleMapper applyArticleMapper;
    private final RedisUtil redisUtil;
    private final CommentMapper commentMapper;
    private final FavoriteMapper favoriteMapper;
    private final CategoryLabelRelMapper categoryLabelRelMapper;
    private final FeignSystem feignSystem;
    private final ObjectMapper objectMapper;

    /**
     * 获取文章列表
     *
     * @param articleListReqVo 查询条件
     * @return 文章列表
     */
    @Override
    public PageInfo<ArticleRespVo> getArticleList(ArticleListReqVo articleListReqVo) {
        String categoryId = articleListReqVo.getCategoryId();
        String title = articleListReqVo.getTitle();
        Integer status = articleListReqVo.getStatus();
        Integer approveStatus = articleListReqVo.getApproveStatus();
        Integer publishType = articleListReqVo.getPublishType();
        Integer pageNo = articleListReqVo.getPageNo();
        Integer pageSize = articleListReqVo.getPageSize();
        if (Objects.isNull(pageSize)) {
            pageSize = DEFAULT_PAGE_SIZE;
        }

        this.checkCategory(categoryId);

        LambdaQueryWrapper<ArticleEntity> wrapper = new LambdaQueryWrapper<>();
        wrapper.orderByDesc(ArticleEntity::getCreateTime);
        /*wrapper.eq(ArticleEntity::getStatus, ArticleStatusEnum.ONLINE.getCode());
        wrapper.eq(ArticleEntity::getPublicType, ArticlePublicTypeEnum.VISIBLE_ALL.getCode());
        wrapper.eq(ArticleEntity::getApproveStatus, ApproveEnum.PASS.getCode());*/
        if (StringUtils.isNotBlank(categoryId)) {
            wrapper.eq(ArticleEntity::getCategoryId, articleListReqVo.getCategoryId());
        }

        if (StringUtils.isNotBlank(title)) {
            wrapper.like(ArticleEntity::getTitle, articleListReqVo.getTitle());
        }

        if (Objects.nonNull(status)) {
            wrapper.eq(ArticleEntity::getStatus, status);
        }

        if (Objects.nonNull(approveStatus)) {
            wrapper.eq(ArticleEntity::getApproveStatus, ApproveEnum.PASS.getCode());
        }

        if (Objects.nonNull(publishType)) {
            wrapper.eq(ArticleEntity::getPublicType, ArticlePublicTypeEnum.VISIBLE_ALL.getCode());
        }

        Page<Object> page = PageHelper.startPage(pageNo, pageSize);
        List<ArticleEntity> articleList = this.baseMapper.selectList(wrapper);
        if (CollectionUtils.isEmpty(articleList)) {
            return new PageInfo<>();
        }

        List<ArticleRespVo> respVos = articleList.stream().map(item -> {
            ArticleRespVo articleRespVo = new ArticleRespVo();
            BeanUtils.copyProperties(item, articleRespVo);
            return articleRespVo;
        }).collect(Collectors.toList());
        PageInfo<ArticleRespVo> pageInfo = new PageInfo<>(respVos);
        pageInfo.setTotal(page.getTotal());
        return pageInfo;


        /*List<String> roleList = StpUtil.getRoleList();
        if (CollectionUtil.isEmpty(roleList)) {
            throw new Blog4jException(ErrorEnum.ROLE_INFO_EMPTY_ERROR);
        }
        String userId = StpUtil.getLoginIdAsString();
        String role = roleList.get(0);
        // 如果是超级管理员  可以查看所有的文章
        if (StringUtils.equals(role, RoleEnum.SUPER_ADMIN.getDesc())) {
            return this.getArticleList(wrapper, articleListReqVo);
        } else if (StringUtils.equals(role, RoleEnum.ORGANIZATION_ADMIN.getDesc())) {
            // 如果是组织管理员  可以查看该组织下的所有的文章
            List<String> userIds = feignUser.getUserIdsByOrganizationAdmin(userId);
            wrapper.in(ArticleEntity::getAuthorId, userIds).or()
                    .eq(ArticleEntity::getPublicType, ArticlePublicTypeEnum.VISIBLE_ALL.getCode());
            return this.getArticleList(wrapper, articleListReqVo);
        } else if (StringUtils.equals(role, RoleEnum.ORDINARY.getDesc())) {
            // 如果是普通用户
            List<OrganizationVo> organizationVoList = feignUser.getOrganizationInfoByUserId(userId);
            if (organizationVoList.isEmpty()) {
                // 如果该用户不是任何组织的成员
                wrapper.eq(ArticleEntity::getPublicType, ArticlePublicTypeEnum.VISIBLE_ALL.getCode());
                return this.getArticleList(wrapper, articleListReqVo);
            } else {
                HashSet<String> idSet = new HashSet<>();
                for (OrganizationVo vo : organizationVoList) {
                    String admin = vo.getOrganizationAdmin();
                    List<String> userIds = feignUser.getUserIdsByOrganizationAdmin(admin);
                    idSet.addAll(userIds);
                }
                PageHelper.startPage(articleListReqVo.getPageNo(), articleListReqVo.getPageSize());
                List<ArticleEntity> articleList = this.baseMapper.getOrdinaryArticleList(idSet, status, categoryId, title);
                if (!articleList.isEmpty()) {
                    List<ArticleRespVo> respVos = articleList.stream().map(article -> {
                        ArticleRespVo articleRespVo = new ArticleRespVo();
                        BeanUtils.copyProperties(article, articleRespVo);
                        return articleRespVo;
                    }).collect(Collectors.toList());
                    return new PageInfo<>(respVos);
                }
            }
        } else if (StringUtils.equals(role, RoleEnum.COMPOSER.getDesc())) {
            // 如果是创作者
            List<OrganizationVo> organizationVoList = feignUser.getOrganizationInfoByUserId(userId);
            List<ArticleEntity> articleList ;
            if (CollectionUtil.isEmpty(organizationVoList)) {
                // 如果该用户不是任何组织的成员
                PageHelper.startPage(articleListReqVo.getPageNo(), articleListReqVo.getPageSize());
                articleList = this.baseMapper.getComposerArticleList1(status, categoryId, title, userId);
            } else {
                HashSet<String> idSet = new HashSet<>();
                for (OrganizationVo vo : organizationVoList) {
                    String admin = vo.getOrganizationAdmin();
                    List<String> userIds = feignUser.getUserIdsByOrganizationAdmin(admin);
                    idSet.addAll(userIds);
                }
                PageHelper.startPage(articleListReqVo.getPageNo(), articleListReqVo.getPageSize());
                articleList = this.baseMapper.getComposerArticleList2(idSet, status, categoryId, title, userId);
            }
            if (!articleList.isEmpty()) {
                List<ArticleRespVo> respVos = articleList.stream().map(article -> {
                    ArticleRespVo articleRespVo = new ArticleRespVo();
                    BeanUtils.copyProperties(article, articleRespVo);
                    return articleRespVo;
                }).collect(Collectors.toList());
                return new PageInfo<>(respVos);
            }
        } else {
            // 该用户是访客
            wrapper.eq(ArticleEntity::getPublicType, ArticlePublicTypeEnum.VISIBLE_ALL.getCode());
            return this.getArticleList(wrapper, articleListReqVo);
        }
        return new PageInfo<>();*/
    }

    /**
     * 获取所有的文章状态
     *
     * @return 所有的文章状态
     */
    @Override
    public List<ArticleStatusRespVo> statusList() {
        List<ArticleStatusRespVo> list = new ArrayList<>();
        ArticleStatusRespVo val1 = ArticleStatusRespVo.builder()
                .code(ArticleStatusEnum.DRAFT.getCode())
                .desc(ArticleStatusEnum.DRAFT.getDesc())
                .build();
        ArticleStatusRespVo val2 = ArticleStatusRespVo.builder()
                .code(ArticleStatusEnum.WAIT.getCode())
                .desc(ArticleStatusEnum.WAIT.getDesc())
                .build();
        ArticleStatusRespVo val3 = ArticleStatusRespVo.builder()
                .code(ArticleStatusEnum.ONLINE.getCode())
                .desc(ArticleStatusEnum.ONLINE.getDesc())
                .build();
        list.add(val3);
        list.add(val2);
        list.add(val1);
        return list;
    }

    /**
     * 根据文章ID删除文章
     *
     * @param articleId 文章ID
     */
    @Transactional(rollbackFor = Exception.class)
    @Override
    public void deleteArticle(String articleId) {
        this.beforeDeleteAndPublish(articleId, 2);
        this.baseMapper.deleteById(articleId);

        // 删除评论
        LambdaQueryWrapper<CommentEntity> wrapper = new LambdaQueryWrapper<CommentEntity>()
                .eq(CommentEntity::getArticleId, articleId);
        commentMapper.delete(wrapper);

        // 删除收藏
        LambdaQueryWrapper<FavoriteEntity> wrapper1 = new LambdaQueryWrapper<FavoriteEntity>()
                .eq(FavoriteEntity::getArticleId, articleId);
        favoriteMapper.delete(wrapper1);
    }

    /**
     * 根据文章ID发布文章
     *
     * @param articleId 文章ID
     */
    @Override
    public void publishArticle(String articleId) {
        ArticleEntity article = this.beforeDeleteAndPublish(articleId, 1);
        article.setStatus(ArticleStatusEnum.ONLINE.getCode())
                .setPublishUserId(StpUtil.getLoginIdAsString())
                .setUpdateTime(CommonUtil.getCurrentDateTime());
        this.baseMapper.updateById(article);
    }

    /**
     * 查询文章详情信息
     *
     * @param articleId 文章ID
     * @return 文章详情信息
     */
    @Override
    public ArticleRespVo info(String articleId) {
        ArticleEntity article = this.baseMapper.selectById(articleId);
        if (Objects.isNull(article)) {
            throw new Blog4jException(ErrorEnum.INVALID_PARAMETER_ERROR);
        }

        ArticleRespVo respVo = new ArticleRespVo();
        BeanUtils.copyProperties(article, respVo);
        return respVo;
    }

    /**
     * 编辑文章信息
     *
     * @param context 更新文章信息的上下文信息
     */
    @Override
    public void updateArticle(UpdateArticleContext context) {
        this.beforeUpdateArticle(context);
        ArticleEntity article = context.getArticle();
        BeanUtils.copyProperties(context, article);
        article.setUpdateTime(CommonUtil.getCurrentDateTime())
                .setCategoryName(context.getCategory().getCategoryName())
                .setLabelName(context.getLabel().getLabelName());
        this.baseMapper.updateById(article);
    }

    /**
     * 创建文章信息
     *
     * @param context 创建文章信息的上下文信息
     */
    @Transactional(rollbackFor = Exception.class)
    @Override
    public void create(CreateArticleContext context) {
        this.beforeCreate(context);
        ArticleEntity article = new ArticleEntity();
        BeanUtils.copyProperties(context, article);
        String articleId = IdGeneratorSnowflakeUtil.snowflakeId();
        String userId = StpUtil.getLoginIdAsString();
        UserInfoVo user = feignUser.getUserInfoByUserId(userId);

        article.setArticleId(articleId)
                .setUpdateTime(CommonUtil.getCurrentDateTime())
                .setCreateTime(CommonUtil.getCurrentDateTime())
                .setDeleted(YesOrNoEnum.NO.getCode())
                .setStick(YesOrNoEnum.NO.getCode())
                .setApproveStatus(ApproveEnum.WAIT_APPROVE.getCode())
                .setViews(0)
                .setLikes(0);
        if (StringUtils.equals(user.getRoleCode(), RoleEnum.SUPER_ADMIN.getDesc())) {
            article.setApproveStatus(ApproveEnum.PASS.getCode());
            if (context.getTimedRelease() == YesOrNoEnum.NO.getCode()) {
                article.setStatus(ArticleStatusEnum.ONLINE.getCode());
            }
        }
        this.baseMapper.insert(article);

        SystemBaseConfigVo systemBaseConfig = this.getSystemBaseConfig();
        if (Objects.equals(systemBaseConfig.getArticleApproveRequire(), YesOrNoEnum.NO.getCode())) {
            // 发布文章不需要审批
            article.setStatus(ArticleStatusEnum.ONLINE.getCode())
                    .setApproveStatus(ApproveEnum.PASS.getCode());
            this.baseMapper.updateById(article);
            return;
        }

        if (StringUtils.equals(user.getRoleCode(), RoleEnum.SUPER_ADMIN.getDesc())) {
            // 超级管理员发布文章不需要审批
            return;
        }

        // 添加一条申请记录到文章申请表中
        List<OrganizationVo> organizationList = feignUser.getOrganizationInfoByUserId(userId);
        String organizationIdStr = "";
        String organizationNameStr = "";
        if (CollectionUtil.isNotEmpty(organizationList)) {
            organizationIdStr = organizationList.stream().map(OrganizationVo::getOrganizationId)
                    .collect(Collectors.joining(CommonConstant.COMMA));
            organizationNameStr = organizationList.stream().map(OrganizationVo::getOrganizationName)
                    .collect(Collectors.joining(CommonConstant.COMMA));
        }

        ApplyArticleEntity applyArticle = ApplyArticleEntity.builder()
                .id(IdGeneratorSnowflakeUtil.snowflakeId())
                .articleId(articleId)
                .articleTitle(context.getTitle())
                .applyUserId(userId)
                .applyUserName(user.getUserName())
                .applyUserRoleId(user.getRoleId())
                .applyUserRoleName(user.getRoleName())
                .organizationId(organizationIdStr)
                .organizationName(organizationNameStr)
                .createTime(CommonUtil.getCurrentDateTime())
                .build();
        applyArticleMapper.insert(applyArticle);
    }

    /**
     * 删除用户名下的文章信息
     *
     * @param vo 用户集合
     */
    @Transactional(rollbackFor = Exception.class)
    @Override
    public void deleteUserArticle(DeleteUserArticleVo vo) {
        List<String> userIds = vo.getUserIds();
        LambdaQueryWrapper<ArticleEntity> wrapper = new LambdaQueryWrapper<ArticleEntity>()
                .in(ArticleEntity::getAuthorId, userIds);
        List<ArticleEntity> articleList = this.baseMapper.selectList(wrapper);
        if (CollectionUtil.isEmpty(articleList)) {
            return;
        }
        Set<String> articleIds = articleList.stream()
                .map(ArticleEntity::getArticleId).collect(Collectors.toSet());
        this.baseMapper.deleteBatchIds(articleIds);

        // 删除文章评论信息
        LambdaQueryWrapper<CommentEntity> wrapper1 = new LambdaQueryWrapper<CommentEntity>()
                .in(CommentEntity::getArticleId, articleIds);
        List<CommentEntity> commentList = commentMapper.selectList(wrapper1);
        if (CollectionUtil.isNotEmpty(commentList)) {
            Set<Integer> commentIdSet = commentList.stream().map(CommentEntity::getCommentId)
                    .collect(Collectors.toSet());
            commentMapper.deleteBatchIds(commentIdSet);
        }

        // 删除用户的收藏文章信息
        LambdaQueryWrapper<FavoriteEntity> wrapper2 = new LambdaQueryWrapper<FavoriteEntity>()
                .in(FavoriteEntity::getArticleId, articleIds);
        List<FavoriteEntity> favoriteList = favoriteMapper.selectList(wrapper2);
        if (CollectionUtil.isNotEmpty(favoriteList)) {
            Set<Integer> favoriteIdSet = favoriteList.stream().map(FavoriteEntity::getId).collect(Collectors.toSet());
            favoriteMapper.deleteBatchIds(favoriteIdSet);
        }
    }

    /**
     * 获取本周排行榜的文章
     *
     * @return 文章列表
     */
    @Override
    public List<ArticleEntity> getViewsArticle() {
        LambdaQueryWrapper<ArticleEntity> wrapper = new LambdaQueryWrapper<ArticleEntity>()
                .eq(ArticleEntity::getStatus, ArticleStatusEnum.ONLINE.getCode())
                .eq(ArticleEntity::getPublicType, ArticlePublicTypeEnum.VISIBLE_ALL.getCode())
                .eq(ArticleEntity::getApproveStatus, ApproveEnum.PASS.getCode())
                .orderByDesc(ArticleEntity::getViews)
                .last(CommonConstant.LIMIT_TEN);
        return this.baseMapper.selectList(wrapper);
    }

    /**
     * 点赞或取消点赞文章
     *
     * @param reqVo 请求信息
     */
    @Override
    public void likeArticle(LikeArticleReqVo reqVo) {
        String articleId = reqVo.getArticleId();
        Integer likeStatus = reqVo.getLikeStatus();

        ArticleEntity article = this.baseMapper.selectById(articleId);
        if (Objects.isNull(article)) {
            throw new Blog4jException(ErrorEnum.ARTICLE_NOT_EXIST_ERROR);
        }

        if (!Objects.equals(YesOrNoEnum.YES.getCode(), likeStatus) &&
                !Objects.equals(YesOrNoEnum.NO.getCode(), likeStatus)) {
            throw new Blog4jException(ErrorEnum.INVALID_PARAMETER_ERROR);
        }

        Object cacheVal = redisUtil.get(CacheConstants.LIKE_ARTICLE_KEY + articleId);
        Integer currentCacheVal;
        if (Objects.isNull(cacheVal)) {
            currentCacheVal = Objects.equals(YesOrNoEnum.YES.getCode(), likeStatus) ? 1 : -1;
        } else {
            int cacheVal1 = Integer.parseInt((String) cacheVal);
            currentCacheVal = Objects.equals(YesOrNoEnum.YES.getCode(), likeStatus) ?
                    cacheVal1 + 1 : cacheVal1 - 1;
        }
        redisUtil.set(CacheConstants.LIKE_ARTICLE_KEY + articleId,
                String.valueOf(currentCacheVal), CacheConstants.LIKE_ARTICLE_EXPIRE_TIME);
    }

    /**
     * 收藏文章
     *
     * @param reqVo 请求信息
     */
    @Override
    public void favorite(FavoriteReqVo reqVo) {
        String articleId = reqVo.getArticleId();
        Integer favoriteStatus = reqVo.getFavoriteStatus();

        if (!Objects.equals(YesOrNoEnum.YES.getCode(), favoriteStatus) &&
                !Objects.equals(YesOrNoEnum.NO.getCode(), favoriteStatus)) {
            throw new Blog4jException(ErrorEnum.INVALID_PARAMETER_ERROR);
        }

        ArticleEntity article = this.baseMapper.selectById(articleId);
        if (Objects.isNull(article)) {
            throw new Blog4jException(ErrorEnum.ARTICLE_NOT_EXIST_ERROR);
        }

        String userId = StpUtil.getLoginIdAsString();
        Object cacheVal = redisUtil.get(CacheConstants.FAVORITE_ARTICLE_KEY
                + userId + CacheConstants.SPLIT + articleId);
        Integer currentCacheVal;
        if (Objects.isNull(cacheVal)) {
            currentCacheVal = Objects.equals(YesOrNoEnum.YES.getCode(), favoriteStatus) ? 1 : 0;
        } else {
            int cacheVal1 = Integer.parseInt((String) cacheVal);
            currentCacheVal = Objects.equals(YesOrNoEnum.YES.getCode(), favoriteStatus) ?
                    cacheVal1 + 1 : cacheVal1 - 1;
        }
        redisUtil.set(CacheConstants.FAVORITE_ARTICLE_KEY
                        + userId + CacheConstants.SPLIT + articleId,
                String.valueOf(currentCacheVal), CacheConstants.FAVORITE_ARTICLE_EXPIRE_TIME);
    }

    /**
     * 文章浏览量
     *
     * @param articleId 文章ID
     */
    @Override
    public void articleViews(String articleId) {
        ArticleEntity article = this.baseMapper.selectById(articleId);
        if (Objects.isNull(article)) {
            throw new Blog4jException(ErrorEnum.ARTICLE_NOT_EXIST_ERROR);
        }

        Object cacheVal = redisUtil.get(CacheConstants.VIEWS_ARTICLE_KEY + articleId);
        int cacheVal1 = 1;
        if (Objects.nonNull(cacheVal)) {
            cacheVal1 = Integer.parseInt((String) cacheVal) + 1;
        }
        redisUtil.set(CacheConstants.VIEWS_ARTICLE_KEY + articleId, String.valueOf(cacheVal1), CacheConstants.VIEWS_ARTICLE_EXPIRE_TIME);
    }

    /**
     * 获取当前文章的上一篇和下一篇
     *
     * @param articleId 文章ID
     * @return 文章信息
     */
    @Override
    public Map<String, ArticleRespVo> getNextAndPreviousArticle(String articleId) {
        Map<String, ArticleRespVo> resMap = new HashMap<>();
        LambdaQueryWrapper<ArticleEntity> wrapper = new LambdaQueryWrapper<ArticleEntity>()
                .eq(ArticleEntity::getStatus, ArticleStatusEnum.ONLINE.getCode())
                .eq(ArticleEntity::getApproveStatus, ApproveEnum.PASS.getCode())
                .orderByDesc(ArticleEntity::getCreateTime);
        List<ArticleEntity> articleList = this.baseMapper.selectList(wrapper);
        if (CollectionUtil.isEmpty(articleList)) {
            return null;
        }

        if (CollectionUtil.size(articleList) == 1) {
            resMap.put("next", null);
            resMap.put("previous", null);
        }

        for(int index = 0; index < articleList.size(); index++) {
            if (StringUtils.equals(articleList.get(index).getArticleId(), articleId)) {
                if (Objects.equals(0, index)) {
                    ArticleRespVo articleRespVo = new ArticleRespVo();
                    BeanUtils.copyProperties(articleList.get(index + 1), articleRespVo);
                    resMap.put("next", articleRespVo);
                    resMap.put("previous", null);
                } else if (Objects.equals(articleList.size() - 1, index)) {
                    ArticleRespVo articleRespVo = new ArticleRespVo();
                    BeanUtils.copyProperties(articleList.get(index - 1), articleRespVo);
                    resMap.put("previous", articleRespVo);
                    resMap.put("next", null);
                } else {
                    if (Objects.nonNull(articleList.get(index - 1))) {
                        ArticleRespVo articleRespVo = new ArticleRespVo();
                        BeanUtils.copyProperties(articleList.get(index - 1), articleRespVo);
                        resMap.put("previous", articleRespVo);
                    }

                    if (Objects.nonNull(articleList.get(index + 1))) {
                        ArticleRespVo articleRespVo = new ArticleRespVo();
                        BeanUtils.copyProperties(articleList.get(index + 1), articleRespVo);
                        resMap.put("next", articleRespVo);
                    }
                }
            }
        }
        return resMap;
    }

    /**
     * 获取推荐文章列表
     *
     * @param articleId 文章ID
     * @return 推荐文章列表
     */
    @Override
    public List<ArticleRespVo> getRecommendArticle(String articleId) {
        ArticleEntity article = this.baseMapper.selectById(articleId);
        if (Objects.isNull(article)) {
            throw new Blog4jException(ErrorEnum.ARTICLE_NOT_EXIST_ERROR);
        }

        String categoryId = article.getCategoryId();
        String labelId = article.getLabelId();

        LambdaQueryWrapper<ArticleEntity> wrapper = new LambdaQueryWrapper<ArticleEntity>()
                .eq(ArticleEntity::getCategoryId, categoryId).or()
                .eq(ArticleEntity::getLabelId, labelId)
                .eq(ArticleEntity::getStatus, ArticleStatusEnum.ONLINE.getCode())
                .eq(ArticleEntity::getApproveStatus, ApproveEnum.PASS.getCode())
                .orderByDesc(ArticleEntity::getCreateTime)
                .last(CommonConstant.LIMIT_TEN);
        List<ArticleEntity> articleList = this.baseMapper.selectList(wrapper);
        if (CollectionUtil.isEmpty(articleList)) {
            return null;
        }
        return articleList.stream().map(item -> {
            ArticleRespVo articleRespVo = new ArticleRespVo();
            BeanUtils.copyProperties(item, articleRespVo);
            return articleRespVo;
        }).collect(Collectors.toList());
    }

    /**
     * 获取最新文章列表
     *
     * @return 最新文章列表
     */
    @Override
    public List<ArticleRespVo> getNewArticleList() {
        LambdaQueryWrapper<ArticleEntity> wrapper = new LambdaQueryWrapper<ArticleEntity>()
                .eq(ArticleEntity::getStatus, ArticleStatusEnum.ONLINE.getCode())
                .eq(ArticleEntity::getApproveStatus, ApproveEnum.PASS.getCode())
                .orderByDesc(ArticleEntity::getCreateTime)
                .last(CommonConstant.LIMIT_TEN);

        List<ArticleEntity> articleList = this.baseMapper.selectList(wrapper);
        if (CollectionUtil.isEmpty(articleList)) {
            return null;
        }
        return articleList.stream().map(item -> {
            ArticleRespVo articleRespVo = new ArticleRespVo();
            BeanUtils.copyProperties(item, articleRespVo);
            return articleRespVo;
        }).collect(Collectors.toList());
    }

    /**
     * 根据分类ID获取文章信息
     *
     * @param reqVo 请求信息
     * @return 文章信息
     */
    @Override
    public PageInfo<ArticleRespVo> getByCategoryId(ArticleByCategoryIdReqVo reqVo) {
        Integer pageNo = reqVo.getPageNo();
        Integer pageSize = reqVo.getPageSize();
        String categoryId = reqVo.getCategoryId();

        CategoryEntity category = categoryMapper.selectById(categoryId);
        if (Objects.isNull(category)) {
            throw new Blog4jException(ErrorEnum.CATEGORY_INFO_EMPTY_ERROR);
        }

        Page<Object> page = PageHelper.startPage(pageNo, pageSize);
        LambdaQueryWrapper<ArticleEntity> wrapper = new LambdaQueryWrapper<ArticleEntity>()
                .eq(ArticleEntity::getStatus, ArticleStatusEnum.ONLINE.getCode())
                .eq(ArticleEntity::getApproveStatus, ApproveEnum.PASS.getCode())
                .eq(ArticleEntity::getCategoryId, categoryId)
                .orderByDesc(ArticleEntity::getCreateTime);
        List<ArticleEntity> articleList = this.baseMapper.selectList(wrapper);
        if (CollectionUtil.isEmpty(articleList)) {
            return new PageInfo<>();
        }

        List<ArticleRespVo> respVos = articleList.stream().map(article -> {
            ArticleRespVo articleRespVo = new ArticleRespVo();
            BeanUtils.copyProperties(article, articleRespVo);
            return articleRespVo;
        }).collect(Collectors.toList());

        PageInfo<ArticleRespVo> pageInfo = new PageInfo<>(respVos);
        pageInfo.setTotal(page.getTotal());
        return pageInfo;
    }

    /**
     * 获取用户的文章数、分类数
     *
     * @return 用户的文章数、分类数
     */
    @Override
    public ArticleCategoryNumsRespVo getArticleCategoryNums(String userId) {
        if (StringUtils.isBlank(userId)) {
            userId = StpUtil.getLoginIdAsString();
        }
        UserInfoVo userInfoVo = feignUser.getUserInfoByUserId(userId);
        if (StringUtils.isBlank(userInfoVo.getUserId())) {
            throw new Blog4jException(ErrorEnum.USER_NOT_EXIST_ERROR);
        }

        LambdaQueryWrapper<ArticleEntity> wrapper = new LambdaQueryWrapper<ArticleEntity>()
                .eq(ArticleEntity::getAuthorId, userId);
        Integer articleCount = this.baseMapper.selectCount(wrapper);

        LambdaQueryWrapper<CategoryEntity> wrapper1 = new LambdaQueryWrapper<CategoryEntity>()
                .eq(CategoryEntity::getCreater, userId);
        Integer categoryCount = categoryMapper.selectCount(wrapper1);

        LambdaQueryWrapper<FavoriteEntity> wrapper2 = new LambdaQueryWrapper<FavoriteEntity>()
                .eq(FavoriteEntity::getUserId, userId);
        Integer favoriteCount = favoriteMapper.selectCount(wrapper2);

        List<UserInfoVo> fansList = feignUser.getFansListByUserId(userId);

        return ArticleCategoryNumsRespVo
                .builder()
                .categoryCount(categoryCount)
                .articleCount(articleCount)
                .favoriteCount(favoriteCount)
                .fansCount(CollectionUtil.size(fansList))
                .build();
    }

    /**
     * 获取用户的文章
     *
     * @param reqVo 请求信息
     * @return 用户文章
     */
    @Override
    public PageInfo<ArticleRespVo> getUserArticle(UserArticleReqVo reqVo) {
        Integer pageNo = reqVo.getPageNo();
        Integer pageSize = reqVo.getPageSize();
        Integer status = reqVo.getStatus();
        String userId = reqVo.getUserId();
        if (StringUtils.isBlank(userId)) {
            userId = StpUtil.getLoginIdAsString();
        }

        LambdaQueryWrapper<ArticleEntity> wrapper = new LambdaQueryWrapper<ArticleEntity>()
                .orderByDesc(ArticleEntity::getCreateTime)
                .eq(ArticleEntity::getAuthorId, userId);
        if (Objects.equals(status, ArticleStatusEnum.ONLINE.getCode())) {
            wrapper.eq(ArticleEntity::getStatus, ArticleStatusEnum.ONLINE.getCode());
        } else if (Objects.equals(status, ArticleStatusEnum.DRAFT.getCode())) {
            wrapper.eq(ArticleEntity::getStatus, ArticleStatusEnum.DRAFT.getCode());
        } else if (Objects.equals(status, ArticleStatusEnum.WAIT.getCode())) {
            wrapper.eq(ArticleEntity::getStatus, ArticleStatusEnum.WAIT.getCode());
        }

        Page<Object> page = PageHelper.startPage(pageNo, pageSize);
        List<ArticleEntity> articleList = this.baseMapper.selectList(wrapper);
        if (CollectionUtil.isEmpty(articleList)) {
            return new PageInfo<>(new ArrayList<>());
        }
        List<ArticleRespVo> respVos = articleList.stream().map(item -> {
            ArticleRespVo articleRespVo = new ArticleRespVo();
            BeanUtils.copyProperties(item, articleRespVo);
            return articleRespVo;
        }).collect(Collectors.toList());
        PageInfo<ArticleRespVo> pageInfo = new PageInfo<>(respVos);
        pageInfo.setTotal(page.getTotal());
        return pageInfo;
    }

    /**
     * 查询用户的收藏文章
     *
     * @param reqVo 请求信息
     * @return 收藏文章
     */
    @Override
    public PageInfo<ArticleRespVo> getFavoriteArticleByUserId(FavoriteArticleByUserIdReqVo reqVo) {
        Integer pageNo = reqVo.getPageNo();
        Integer pageSize = reqVo.getPageSize();
        String userId = reqVo.getUserId();

        UserInfoVo userInfoVo = feignUser.getUserInfoByUserId(userId);
        if (StringUtils.isBlank(userInfoVo.getUserId())) {
            throw new Blog4jException(ErrorEnum.USER_NOT_EXIST_ERROR);
        }

        Page<Object> page = PageHelper.startPage(pageNo, pageSize);
        List<ArticleEntity> articleList = this.baseMapper.getFavoriteArticleByUserId(userId);
        if (CollectionUtil.isEmpty(articleList)) {
            return new PageInfo<>(new ArrayList<>());
        }

        List<ArticleRespVo> respVos = articleList.stream().map(item -> {
            ArticleRespVo articleRespVo = new ArticleRespVo();
            BeanUtils.copyProperties(item, articleRespVo);
            return articleRespVo;
        }).collect(Collectors.toList());

        PageInfo<ArticleRespVo> pageInfo = new PageInfo<>(respVos);
        pageInfo.setTotal(page.getTotal());
        return pageInfo;
    }

    /**
     * 用户是否收藏该文章
     *
     * @param articleId 文章ID
     * @return 结果
     */
    @Override
    public boolean isFavorite(String articleId) {
        ArticleEntity article = this.baseMapper.selectById(articleId);
        if (Objects.isNull(article)) {
            throw new Blog4jException(ErrorEnum.ARTICLE_NOT_EXIST_ERROR);
        }

        String userId = StpUtil.getLoginIdAsString();
        LambdaQueryWrapper<FavoriteEntity> wrapper = new LambdaQueryWrapper<FavoriteEntity>()
                .eq(FavoriteEntity::getArticleId, articleId)
                .eq(FavoriteEntity::getUserId, userId);
        return favoriteMapper.selectCount(wrapper) > 0;
    }

    // ------------------ private -------------------------------------------------------------

    private void checkCategory(String categoryId) {
        if (StringUtils.isBlank(categoryId)) {
            return;
        }
        CategoryEntity category = categoryMapper.selectById(categoryId);
        if (Objects.isNull(category)) {
            log.error("category is not exist");
            throw new Blog4jException(ErrorEnum.INVALID_PARAMETER_ERROR);
        }
    }

    private PageInfo<ArticleRespVo> getArticleList(LambdaQueryWrapper<ArticleEntity> wrapper,
                                                   ArticleListReqVo articleListReqVo) {
        PageHelper.startPage(articleListReqVo.getPageNo(), articleListReqVo.getPageSize());
        List<ArticleEntity> articleList = this.baseMapper.selectList(wrapper);
        if (!articleList.isEmpty()) {
            List<ArticleRespVo> respVos = articleList.stream().map(article -> {
                ArticleRespVo articleRespVo = new ArticleRespVo();
                BeanUtils.copyProperties(article, articleRespVo);
                return articleRespVo;
            }).collect(Collectors.toList());
            return new PageInfo<>(respVos);
        }
        return new PageInfo<>();
    }

    private ArticleEntity beforeDeleteAndPublish(String articleId, Integer type) {
        ArticleEntity article = this.baseMapper.selectById(articleId);
        if (Objects.isNull(article)) {
            throw new Blog4jException(ErrorEnum.INVALID_PARAMETER_ERROR);
        }

        if (Objects.equals(type, 1) ) {
            if (!Objects.equals(ArticleStatusEnum.WAIT.getCode(), article.getStatus())) {
                throw new Blog4jException(ErrorEnum.ARTICLE_STATUS_ILLEGAL);
            }

            if (!Objects.equals(ApproveEnum.PASS.getCode(), article.getApproveStatus())) {
                throw new Blog4jException(ErrorEnum.ARTICLE_APPROVE_NO_PASS_ERROR);
            }
        }

        List<String> roleList = StpUtil.getRoleList();
        if (roleList.isEmpty()) {
            log.error("roleList is empty .");
            throw new Blog4jException(ErrorEnum.ROLE_INFO_EMPTY_ERROR);
        }

        String role = roleList.get(0);
        String userId = StpUtil.getLoginIdAsString();
        String authorId = article.getAuthorId();

        // 如果角色是创作者  只能删除或者发布自己发表的文章
        if (StringUtils.equals(role, RoleEnum.COMPOSER.getDesc()) &&
                !StringUtils.equals(userId, authorId)) {
            throw new Blog4jException(ErrorEnum.NO_PERMISSION_ERROR);
        }

        // 如果角色是组织管理员  只能删除或者发布自己组织下的用户发表的文章
        if (StringUtils.equals(role, RoleEnum.ORGANIZATION_ADMIN.getDesc())) {
            // 获取该组织管理员所有的用户ID列表
            List<String> userIds = feignUser.getUserIdsByOrganizationAdmin(userId);
            if (!userIds.contains(authorId)) {
                throw new Blog4jException(ErrorEnum.NO_PERMISSION_ERROR);
            }
        }
        return article;
    }

    private void beforeUpdateArticle(UpdateArticleContext context) {
        String articleId = context.getArticleId();
        ArticleEntity article = this.baseMapper.selectById(articleId);
        if (Objects.isNull(article)) {
            throw new Blog4jException(ErrorEnum.INVALID_PARAMETER_ERROR);
        }
        context.setArticle(article);

        // 判断分类是否合法
        String categoryId = context.getCategoryId();
        LambdaQueryWrapper<CategoryEntity> wrapper = new LambdaQueryWrapper<CategoryEntity>()
                .eq(CategoryEntity::getCreater, article.getAuthorId())
                .eq(CategoryEntity::getCategoryId, categoryId)
                .eq(CategoryEntity::getStatus, CategoryAndLabelStatusEnum.NORMAL.getCode());
        CategoryEntity category = categoryMapper.selectOne(wrapper);
        if (Objects.isNull(category)) {
            throw new Blog4jException(ErrorEnum.INVALID_PARAMETER_ERROR);
        }
        context.setCategory(category);

        // 判断标签是否合法
        String labelId = context.getLabelId();
        LambdaQueryWrapper<CategoryLabelRelEntity> wrapper1 = new LambdaQueryWrapper<CategoryLabelRelEntity>()
                .eq(CategoryLabelRelEntity::getCategoryId, categoryId)
                .eq(CategoryLabelRelEntity::getLabelId, labelId);
        if (categoryLabelRelMapper.selectCount(wrapper1) <= 0) {
            throw new Blog4jException(ErrorEnum.INVALID_PARAMETER_ERROR);
        }
        LambdaQueryWrapper<LabelEntity> wrapper2 = new LambdaQueryWrapper<LabelEntity>()
                .eq(LabelEntity::getLabelId, labelId)
                .eq(LabelEntity::getStatus, CategoryAndLabelStatusEnum.NORMAL.getCode())
                .eq(LabelEntity::getCreater, article.getAuthorId());
        LabelEntity label = labelMapper.selectOne(wrapper2);
        if (Objects.isNull(label)) {
            throw new Blog4jException(ErrorEnum.INVALID_PARAMETER_ERROR);
        }
        context.setLabel(label);

        List<String> roleList = StpUtil.getRoleList();
        if (roleList.isEmpty()) {
            log.error("roleList is empty .");
            throw new Blog4jException(ErrorEnum.ROLE_INFO_EMPTY_ERROR);
        }

        String roleCode = roleList.get(0);
        String userId = StpUtil.getLoginIdAsString();

        // 如果角色是组织管理员或者创作者，只能编辑自己发表的文章
        if (StringUtils.equals(roleCode, RoleEnum.COMPOSER.getDesc()) ||
                StringUtils.equals(roleCode, RoleEnum.ORGANIZATION_ADMIN.getDesc())) {
            if (!StringUtils.equals(userId, article.getAuthorId())) {
                throw new Blog4jException(ErrorEnum.NO_PERMISSION_ERROR);
            }
        }
    }

    private void beforeCreate(CreateArticleContext context) {
        Integer timedRelease = context.getTimedRelease();
        if (timedRelease == YesOrNoEnum.YES.getCode()) {
            if (StringUtils.isBlank(context.getCronReleaseTime())) {
                throw new Blog4jException(ErrorEnum.INVALID_PARAMETER_ERROR);
            }
        }
        context.setStatus(ArticleStatusEnum.WAIT.getCode());

        Integer articleType = context.getArticleType();
        if (articleType == ArticleTypeEnum.TRANSPORT.getCode()) {
            if (StringUtils.isBlank(context.getCurationLink())) {
                throw new Blog4jException(ErrorEnum.INVALID_PARAMETER_ERROR);
            }
        }

        String userId = StpUtil.getLoginIdAsString();
        context.setUserId(userId);
        UserInfoVo userInfoVo = feignUser.getUserInfoByUserId(userId);
        context.setAuthorName(userInfoVo.getUserName())
                .setAuthorId(userId);

        CategoryEntity category = categoryMapper.selectById(context.getCategoryId());
        if (Objects.isNull(category)) {
            throw new Blog4jException(ErrorEnum.CATEGORY_INFO_EMPTY_ERROR);
        }

        if (Objects.equals(category.getStatus(), CategoryAndLabelStatusEnum.DISABLE.getCode())) {
            throw new Blog4jException(ErrorEnum.INVALID_PARAMETER_ERROR);
        }
        context.setCategoryName(category.getCategoryName());

        LabelEntity label = labelMapper.selectById(context.getLabelId());
        if (Objects.isNull(label)) {
            throw new Blog4jException(ErrorEnum.LABEL_INFO_EMPTY_ERROR);
        }

        if (Objects.equals(label.getStatus(), CategoryAndLabelStatusEnum.DISABLE.getCode())) {
            throw new Blog4jException(ErrorEnum.INVALID_PARAMETER_ERROR);
        }
        context.setLabelName(label.getLabelName());
    }

    private SystemBaseConfigVo getSystemBaseConfig()  {
        Object val = redisUtil.get(CacheConstants.SYSTEM_BASE_CONFIG_KEY);
        if (Objects.isNull(val)) {
            return feignSystem.getBaseSystemConfig();
        }

        try {
            JSONArray jsonArray = JSON.parseArray((String) val);
            JSONObject jsonObject = JSON.parseObject(objectMapper.writeValueAsString(jsonArray.get(1)));
            return JSON.toJavaObject(jsonObject, SystemBaseConfigVo.class);
        } catch (Exception exception) {
            throw new Blog4jException(ErrorEnum.PARSE_ERROR);
        }
    }
}
